package com.smart.community.commons.websocket.handler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.smart.community.commons.websocket.SimpleWebSocketMessage;
import com.smart.community.commons.websocket.WebSocketMessage;
import com.smart.community.commons.websocket.WebSocketMessageType;
import com.smart.community.commons.websocket.WebSocketService;
import com.smart.community.commons.websocket.UserWebSocketSession;
import com.smart.community.commons.websocket.impl.WebSocketServiceImpl;

import lombok.extern.slf4j.Slf4j;

/**
 * WebSocket处理器
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 */
@Component
@Slf4j
public class WebSocketHandler extends TextWebSocketHandler {

    @Autowired
    private WebSocketService webSocketService;

    @Autowired
    private WebSocketServiceImpl webSocketServiceImpl;

    private final ObjectMapper objectMapper = new ObjectMapper();

    // 内存缓存：WebSocket会话映射
    private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        try {
            // 获取用户信息（从拦截器中设置）
            Long userId = (Long) session.getAttributes().get("userId");
            String username = (String) session.getAttributes().get("username");
            String userType = (String) session.getAttributes().get("userType");
            Long propertyCompanyId = (Long) session.getAttributes().get("propertyCompanyId");

            if (userId != null && username != null) {
                // 创建用户会话
                UserWebSocketSession userSession = 
                    new UserWebSocketSession(userId, username, userType, propertyCompanyId);
                userSession.setClientIp(getClientIp(session));
                userSession.setUserAgent(session.getHandshakeHeaders().getFirst("User-Agent"));
                userSession.setStatus(UserWebSocketSession.SessionStatus.CONNECTED);

                // 保存会话
                sessions.put(session.getId(), session);
                
                // 注册用户会话到服务
                webSocketServiceImpl.registerUserSession(userId, session, userSession);

                // 发送连接成功消息
                SimpleWebSocketMessage connectMessage = 
                    new SimpleWebSocketMessage(WebSocketMessageType.CONNECT_SUCCESS.getCode(), "连接建立成功");
                connectMessage.setSenderId(0L); // 系统消息
                connectMessage.setSenderName("SYSTEM");
                sendMessage(session, connectMessage);

                log.info("WebSocket连接建立成功，用户ID: {}, 用户名: {}, 会话ID: {}", 
                    userId, username, session.getId());
            } else {
                log.warn("WebSocket连接建立失败，用户信息为空，会话ID: {}", session.getId());
                session.close();
            }
        } catch (Exception e) {
            log.error("WebSocket连接建立异常，会话ID: {}, 错误: {}", session.getId(), e.getMessage(), e);
            try {
                session.close();
            } catch (IOException ex) {
                log.error("关闭WebSocket连接失败，会话ID: {}", session.getId(), ex);
            }
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        try {
            String payload = message.getPayload();
            log.debug("收到WebSocket消息，会话ID: {}, 消息内容: {}", session.getId(), payload);

            // 解析消息
            SimpleWebSocketMessage wsMessage = objectMapper.readValue(payload, SimpleWebSocketMessage.class);
            
            // 设置发送者信息
            Long userId = (Long) session.getAttributes().get("userId");
            String username = (String) session.getAttributes().get("username");
            wsMessage.setSenderId(userId);
            wsMessage.setSenderName(username);

            // 更新用户活跃时间
            UserWebSocketSession userSession = webSocketService.getUserSession(userId);
            if (userSession != null) {
                userSession.updateLastActiveTime();
            }

            // 处理消息
            handleMessage(session, wsMessage);

        } catch (Exception e) {
            log.error("处理WebSocket消息失败，会话ID: {}, 错误: {}", session.getId(), e.getMessage(), e);
            
            // 发送错误响应
            SimpleWebSocketMessage errorMessage = 
                new SimpleWebSocketMessage("ERROR", "消息处理失败: " + e.getMessage());
            errorMessage.setSenderId(0L); // 系统消息
            errorMessage.setSenderName("SYSTEM");
            sendMessage(session, errorMessage);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        try {
            Long userId = (Long) session.getAttributes().get("userId");
            String username = (String) session.getAttributes().get("username");

            // 移除会话
            sessions.remove(session.getId());

            // 注销用户会话
            if (userId != null) {
                webSocketServiceImpl.unregisterUserSession(userId);
            }

            log.info("WebSocket连接关闭，用户ID: {}, 用户名: {}, 会话ID: {}, 状态: {}", 
                userId, username, session.getId(), status);
        } catch (Exception e) {
            log.error("处理WebSocket连接关闭异常，会话ID: {}, 错误: {}", session.getId(), e.getMessage(), e);
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        try {
            Long userId = (Long) session.getAttributes().get("userId");
            String username = (String) session.getAttributes().get("username");

            log.error("WebSocket传输错误，用户ID: {}, 用户名: {}, 会话ID: {}, 错误: {}", 
                userId, username, session.getId(), exception.getMessage(), exception);

            // 发送错误消息
            SimpleWebSocketMessage errorMessage = 
                new SimpleWebSocketMessage("ERROR", "连接传输错误: " + exception.getMessage());
            errorMessage.setSenderId(0L); // 系统消息
            errorMessage.setSenderName("SYSTEM");
            sendMessage(session, errorMessage);

            // 关闭连接
            if (session.isOpen()) {
                session.close();
            }
        } catch (Exception e) {
            log.error("处理WebSocket传输错误异常，会话ID: {}, 错误: {}", session.getId(), e.getMessage(), e);
        }
    }

    /**
     * 处理消息
     */
    private void handleMessage(WebSocketSession session, WebSocketMessage message) throws IOException {
        String messageType = message.getMessageType();
        Long userId = message.getSenderId();

        if (userId == null) {
            sendErrorMessage(session, "发送者ID不能为空");
            return;
        }

        switch (messageType) {
            case "JOIN_ROOM":
                handleJoinRoom(userId, message);
                break;
            case "LEAVE_ROOM":
                handleLeaveRoom(userId, message);
                break;
            case "CHAT":
                handleChatMessage(userId, message);
                break;
            case "PING":
                handlePing(session, message);
                break;
            case "HEARTBEAT":
                handleHeartbeat(session, message);
                break;
            case "GET_ONLINE_USERS":
                handleGetOnlineUsers(session, message);
                break;
            case "GET_ROOM_USERS":
                handleGetRoomUsers(session, message);
                break;
            default:
                log.warn("未知的消息类型: {}", messageType);
                sendErrorMessage(session, "未知的消息类型: " + messageType);
        }
    }

    /**
     * 处理加入房间
     */
    private void handleJoinRoom(Long userId, WebSocketMessage message) {
        try {
            String roomId = (String) message.getContent();
            if (roomId == null || roomId.trim().isEmpty()) {
                log.warn("加入房间失败，房间ID为空，用户ID: {}", userId);
                return;
            }

            boolean success = webSocketService.joinRoom(userId, roomId);
            if (success) {
                log.info("用户加入房间成功，用户ID: {}, 房间ID: {}", userId, roomId);
            } else {
                log.warn("用户加入房间失败，用户ID: {}, 房间ID: {}", userId, roomId);
            }
        } catch (Exception e) {
            log.error("处理加入房间消息失败，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
        }
    }

    /**
     * 处理离开房间
     */
    private void handleLeaveRoom(Long userId, WebSocketMessage message) {
        try {
            String roomId = (String) message.getContent();
            if (roomId == null || roomId.trim().isEmpty()) {
                log.warn("离开房间失败，房间ID为空，用户ID: {}", userId);
                return;
            }

            boolean success = webSocketService.leaveRoom(userId, roomId);
            if (success) {
                log.info("用户离开房间成功，用户ID: {}, 房间ID: {}", userId, roomId);
            } else {
                log.warn("用户离开房间失败，用户ID: {}, 房间ID: {}", userId, roomId);
            }
        } catch (Exception e) {
            log.error("处理离开房间消息失败，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
        }
    }

    /**
     * 处理聊天消息
     */
    private void handleChatMessage(Long userId, WebSocketMessage message) {
        try {
            String roomId = message.getTargetRoom();
            if (roomId == null || roomId.trim().isEmpty()) {
                log.warn("发送聊天消息失败，房间ID为空，用户ID: {}", userId);
                return;
            }

            // 发送消息到房间
            webSocketService.sendToRoom(roomId, message);
            log.info("聊天消息发送成功，用户ID: {}, 房间ID: {}", userId, roomId);
        } catch (Exception e) {
            log.error("处理聊天消息失败，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
        }
    }

    /**
     * 处理Ping消息
     */
    private void handlePing(WebSocketSession session, WebSocketMessage message) throws IOException {
        // 发送Pong响应
        SimpleWebSocketMessage pongMessage = new SimpleWebSocketMessage(WebSocketMessageType.PONG.getCode(), "pong");
        pongMessage.setSenderId(0L); // 系统消息
        pongMessage.setSenderName("SYSTEM");
        sendMessage(session, pongMessage);
    }

    /**
     * 处理心跳消息
     */
    private void handleHeartbeat(WebSocketSession session, WebSocketMessage message) throws IOException {
        // 发送心跳响应
        SimpleWebSocketMessage heartbeatResponse = new SimpleWebSocketMessage(WebSocketMessageType.HEARTBEAT_RESPONSE.getCode(), "pong");
        heartbeatResponse.setSenderId(0L); // 系统消息
        heartbeatResponse.setSenderName("SYSTEM");
        sendMessage(session, heartbeatResponse);
    }

    /**
     * 处理获取在线用户请求
     */
    private void handleGetOnlineUsers(WebSocketSession session, WebSocketMessage message) throws IOException {
        try {
            java.util.List<UserWebSocketSession> onlineUsers = webSocketService.getOnlineUsers();
            
            SimpleWebSocketMessage response = new SimpleWebSocketMessage("ONLINE_USERS", onlineUsers);
            response.setSenderId(0L); // 系统消息
            response.setSenderName("SYSTEM");
            sendMessage(session, response);
        } catch (Exception e) {
            log.error("获取在线用户失败，错误: {}", e.getMessage(), e);
            sendErrorMessage(session, "获取在线用户失败: " + e.getMessage());
        }
    }

    /**
     * 处理获取房间用户请求
     */
    private void handleGetRoomUsers(WebSocketSession session, WebSocketMessage message) throws IOException {
        try {
            String roomId = (String) message.getContent();
            if (roomId == null || roomId.trim().isEmpty()) {
                sendErrorMessage(session, "房间ID不能为空");
                return;
            }

            java.util.List<UserWebSocketSession> roomUsers = webSocketService.getRoomUsers(roomId);
            
            SimpleWebSocketMessage response = new SimpleWebSocketMessage("ROOM_USERS", roomUsers);
            response.setSenderId(0L); // 系统消息
            response.setSenderName("SYSTEM");
            sendMessage(session, response);
        } catch (Exception e) {
            log.error("获取房间用户失败，错误: {}", e.getMessage(), e);
            sendErrorMessage(session, "获取房间用户失败: " + e.getMessage());
        }
    }

    /**
     * 发送消息
     */
    public void sendMessage(WebSocketSession session, WebSocketMessage message) throws IOException {
        try {
            String messageJson = objectMapper.writeValueAsString(message);
            session.sendMessage(new TextMessage(messageJson));
        } catch (Exception e) {
            log.error("发送WebSocket消息失败，会话ID: {}, 错误: {}", session.getId(), e.getMessage(), e);
        }
    }

    /**
     * 发送错误消息
     */
    private void sendErrorMessage(WebSocketSession session, String errorMessage) throws IOException {
        SimpleWebSocketMessage errorMsg = new SimpleWebSocketMessage("ERROR", errorMessage);
        errorMsg.setSenderId(0L); // 系统消息
        errorMsg.setSenderName("SYSTEM");
        sendMessage(session, errorMsg);
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp(WebSocketSession session) {
        String clientIp = session.getHandshakeHeaders().getFirst("X-Forwarded-For");
        if (clientIp == null) {
            clientIp = session.getHandshakeHeaders().getFirst("X-Real-IP");
        }
        if (clientIp == null) {
            clientIp = session.getRemoteAddress().getAddress().getHostAddress();
        }
        return clientIp;
    }
}
